#!/usr/bin/env python
# -*- coding: utf-8 -*-

import logging
import socket
import struct
import threading
import time
import frame
import StorageEngine

class Server(object):
    '''
        サーバクラス
    '''

    RECVSIZE = 65535
    
    def __init__(self, bind=(), listen=5, storage=None, ipCam=None):
        '''
            サーバソケットを初期化
            受け入れIPアドレス、接続順番待ち指定
        '''
        self.bind    = bind
        self.listen  = listen
        self.storage = storage
        self.ipCam   = ipCam

    def start(self):
        '''
            ソケット接続待ちループ
        '''
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.socket.bind(self.bind)
        self.socket.listen(self.listen)

        self.threads  = []
        self.sequence = 1

        while True:
            (clientsocket, address) = self.socket.accept()
            logging.debug("Accepted : %s:%s" % (address[0], address[1]) )

            t = Process(name=str(self.sequence), args=(clientsocket, address, self))
            self.threads.append(t)
            t.start()

            self.sequence = self.sequence + 1

        self.socket.close()

class Process(threading.Thread):
    '''
        クライアントに対する処理
        リクエストキュー取り出し、レスポンス
    '''

    def __init__(self, group=None, target=None, name=None,
                args=(), kwargs=None, verbose=None):
        '''
            コンストラクタ
        '''
        threading.Thread.__init__(self, group=group, target=target,
                name=name, verbose=verbose)

        self.socket  = args[0]  # クライアントソケット
        self.address = args[1]  # クライアントIPアドレス, ポート
        self.server  = args[2]  # サーバオブジェクト

        self.pf_resptable = [
            { 'Type': frame.CAMERA_LIST,                'Func': self.respCameraList              },
            { 'Type': frame.CAMERA_SNAPSHOT,            'Func': self.respCameraSnapshot          },

            { 'Type': frame.CAMERA_MOVIE_CAPTURE_START, 'Func': self.respCameraMovieCaptureStart },
            { 'Type': frame.CAMERA_MOVIE_CAPTURE_STOP,  'Func': self.respCameraMovieCaptureStop  },
            { 'Type': frame.STORAGE_MOVIE_FRAME_ALL,    'Func': self.respStorageMovieFrameAll    },
            { 'Type': frame.STORAGE_MOVIE_FRAME_FIRST,  'Func': self.respStorageMovieFrameFirst  },
            { 'Type': frame.STORAGE_MOVIE_FRAME_LAST,   'Func': self.respStorageMovieFrameLast   },
            { 'Type': frame.STORAGE_MOVIE_FRAME_RANGE,  'Func': self.respStorageMovieFrameRange  },
            { 'Type': frame.STORAGE_MOVIE_GETFRAME,     'Func': self.respStorageMovieGetFrame    },

            { 'Type': frame.CAMERA_AUDIO_CAPTURE_START, 'Func': self.respCameraAudioCaptureStart },
            { 'Type': frame.CAMERA_AUDIO_CAPTURE_STOP,  'Func': self.respCameraAudioCaptureStop  },
            { 'Type': frame.STORAGE_AUDIO_FRAME_ALL,    'Func': self.respStorageAudioFrameAll    },
            { 'Type': frame.STORAGE_AUDIO_FRAME_FIRST,  'Func': self.respStorageAudioFrameFirst  },
            { 'Type': frame.STORAGE_AUDIO_FRAME_LAST,   'Func': self.respStorageAudioFrameLast   },
            { 'Type': frame.STORAGE_AUDIO_FRAME_RANGE,  'Func': self.respStorageAudioFrameRange  },
            { 'Type': frame.STORAGE_AUDIO_GETFRAME,     'Func': self.respStorageAudioGetFrame    },
        ]

    def resp_hashcall(self, Type, param=None ):
        for pti in self.pf_resptable:
            if pti['Type'] == Type:
                logging.debug("type = %x" % Type)
                return pti['Func'](param)

        return None

    def __get_camera_response(self, resp):
        '''
            カメラプラグインのレスポンスルールをチェックし
            Object, Message形式のレスポンスに加工する
        '''
        if 'Success' not in resp:
            logging.warning('failed plugin implement rule(not found Success field)') 
            return None, 'failed plugin implement rule(not found Success field)'

        if resp['Success'] is False:
            if 'Message' not in resp:
                logging.warning('failed plugin implement rule(not found Message field)') 
                return None, 'failed plugin implement rule(not found Message field)'
            else:
                return None, resp['Message']

        if 'Response' not in resp:
            logging.warning('failed plugin implement rule(not found Response field)') 
            return None, 'failed plugin implement rule(not found Response field)'

        if resp['Response'] is None:
            logging.warning('failed plugin implement rule(Response is None)')
            return None, 'failed plugin implement rule(Response is None)'

        return resp['Response'], None

    def respCameraList(self, param):
        '''
            アクセスできるカメラ一覧を返す
            {'Success':True, 'Response':object}
            {'Success':False, 'Message':string}
        '''

        Object = self.server.ipCam.getCameraList()
        return {'Success':True, 'Response':Object}

    def respCameraSnapshot(self, param):
        '''
            スナップショット
            {'Success':True, 'Response':object}
            {'Success':False, 'Message':string}
        '''
        if 'cid' not in param:
            return None

        target = param['cid']
        logging.debug("target = %s" % target)

        resp = self.server.ipCam.camera[target].getSnapshot()
        Object, Message = self.__get_camera_response(resp)
        if not Object:
            return {'Success':False, 'Message':Message}

        return {'Success':True, 'Response':Object }

    def respCameraMovieCaptureStart(self, param):
        '''
            カメラの動画ストリーミングを開始する
            {'Success':True, 'Response':object}
            {'Success':False, 'Message':string}
        '''
        if 'cid' not in param:
            return None

        target = param['cid']
        logging.debug("target = %s" % target)

        resp = self.server.ipCam.camera[target].startMovieCapture(target, self.server.storage)
        Object, Message = self.__get_camera_response(resp)
        if not Object:
            return {'Success':False, 'Message':Message}

        return {'Success':True, 'Response':Object}

    def respCameraMovieCaptureStop(self, param):
        '''
            カメラの動画ストリーミングを停止する
            {'Success':True, 'Response':object}
            {'Success':False, 'Message':string}
        '''
        if 'cid' not in param:
            return None

        target = param['cid']
        logging.debug("target = %s" % target)

        resp = self.server.ipCam.camera[target].endMovieCapture()
        Object, Message = self.__get_camera_response(resp)
        if not Object:
            return {'Success':False, 'Message':Message}

        return {'Success':True, 'Response':Object}

    def respStorageMovieFrameAll(self, param):
        '''
            ストレージから保存された全フレーム一覧を取得する
            {'Success':True, 'Response':object}
            {'Success':False, 'Message':string}
        '''
        if 'cid' not in param:
            return {'Success':False, 'Message':'Request parameter error(cid)'}

        target = param['cid']
        logging.debug("target = %s" % target)

        Object = self.server.storage.get_frame_list(target, StorageEngine.Controller.QUERY_FRAME_ALL, '.jpg')
        return {'Success':True, 'Response':Object}

    def respStorageMovieFrameFirst(self, param):
        '''
            ストレージから保存された一番古いフレーム一覧を取得する
            {'Success':True, 'Response':object}
            {'Success':False, 'Message':string}
        '''
        if 'cid' not in param:
            return {'Success':False, 'Message':'Request parameter error(cid)'}

        target = param['cid']
        logging.debug("target = %s" % target)

        Object = self.server.storage.get_frame_list(target, StorageEngine.Controller.QUERY_FRAME_FIRST, '.jpg')
        return {'Success':True, 'Response':Object}

    def respStorageMovieFrameLast(self, param):
        '''
            ストレージから保存された一番新しいフレーム一覧を取得する
            {'Success':True, 'Response':object}
            {'Success':False, 'Message':string}
        '''
        if 'cid' not in param:
            return {'Success':False, 'Message':'Request parameter error(cid)'}

        target = param['cid']
        logging.debug("target = %s" % target)

        Object = self.server.storage.get_frame_list(target, StorageEngine.Controller.QUERY_FRAME_LAST, '.jpg')
        return {'Success':True, 'Response':Object}

    def respStorageMovieFrameRange(self, param):
        '''
            ストレージから保存された期間に該当するフレーム一覧を取得する
            {'Success':True, 'Response':object}
            {'Success':False, 'Message':string}
        '''
        if 'cid' not in param:
            return {'Success':False, 'Message':'Request parameter error(cid)'}

        target = param['cid']
        logging.debug("target = %s" % target)
        
        if 'range' not in param:
            return {'Success':False, 'Message':'Request parameter error(range)'}

        query = param['range']
        logging.debug("query = %s" % query)

        Object = self.server.storage.get_frame_list(target, query, '.jpg')
        return {'Success':True, 'Response':Object}

    def respStorageMovieGetFrame(self, param):
        '''
            ストレージからフレームの実体を取得する
            {'Success':True, 'Response':object}
            {'Success':False, 'Message':string}
        '''
        if 'framename' not in param:
            return {'Success':False, 'Message':'Request parameter error(framename)'}

        framename = param['framename']
        Object    = self.server.storage.get_frame(framename, '.jpg')
        return {'Success':True, 'Response':Object}

    def respCameraAudioCaptureStart(self, param):
        '''
            カメラの音声ストリーミングを開始する
            {'Success':True, 'Response':object}
            {'Success':False, 'Message':string}
        '''
        if 'cid' not in param:
            return None

        target = param['cid']
        logging.debug("target = %s" % target)

        resp = self.server.ipCam.camera[target].startAudioCapture(target, self.server.storage)
        Object, Message = self.__get_camera_response(resp)
        if not Object:
            return {'Success':False, 'Message':Message}

        return {'Success':True, 'Response':Object}

    def respCameraAudioCaptureStop(self, param):
        '''
            カメラの音声ストリーミングを停止する
            {'Success':True, 'Response':object}
            {'Success':False, 'Message':string}
        '''
        if 'cid' not in param:
            return None

        target = param['cid']
        logging.debug("target = %s" % target)

        resp = self.server.ipCam.camera[target].endAudioCapture()
        Object, Message = self.__get_camera_response(resp)
        if not Object:
            return {'Success':False, 'Message':Message}

        return {'Success':True, 'Response':Object}

    def respStorageAudioFrameAll(self, param):
        '''
            ストレージから保存された全フレーム一覧を取得する
            {'Success':True, 'Response':object}
            {'Success':False, 'Message':string}
        '''
        if 'cid' not in param:
            return {'Success':False, 'Message':'Request parameter error(cid)'}

        target = param['cid']
        logging.debug("target = %s" % target)

        Object = self.server.storage.get_frame_list(target, StorageEngine.Controller.QUERY_FRAME_ALL, '.pcm')
        return {'Success':True, 'Response':Object}

    def respStorageAudioFrameFirst(self, param):
        '''
            ストレージから保存された一番古いフレーム一覧を取得する
            {'Success':True, 'Response':object}
            {'Success':False, 'Message':string}
        '''
        if 'cid' not in param:
            return {'Success':False, 'Message':'Request parameter error(cid)'}

        target = param['cid']
        logging.debug("target = %s" % target)

        Object = self.server.storage.get_frame_list(target, StorageEngine.Controller.QUERY_FRAME_FIRST, '.pcm')
        return {'Success':True, 'Response':Object}

    def respStorageAudioFrameLast(self, param):
        '''
            ストレージから保存された一番新しいフレーム一覧を取得する
            {'Success':True, 'Response':object}
            {'Success':False, 'Message':string}
        '''
        if 'cid' not in param:
            return {'Success':False, 'Message':'Request parameter error(cid)'}

        target = param['cid']
        logging.debug("target = %s" % target)

        Object = self.server.storage.get_frame_list(target, StorageEngine.Controller.QUERY_FRAME_LAST, '.pcm')
        return {'Success':True, 'Response':Object}

    def respStorageAudioFrameRange(self, param):
        '''
            ストレージから保存された期間に該当するフレーム一覧を取得する
            {'Success':True, 'Response':object}
            {'Success':False, 'Message':string}
        '''
        if 'cid' not in param:
            return {'Success':False, 'Message':'Request parameter error(cid)'}

        target = param['cid']
        logging.debug("target = %s" % target)
        
        if 'range' not in param:
            return {'Success':False, 'Message':'Request parameter error(range)'}

        query = param['range']
        logging.debug("query = %s" % query)

        Object = self.server.storage.get_frame_list(target, query, '.pcm')
        return {'Success':True, 'Response':Object}

    def respStorageAudioGetFrame(self, param):
        '''
            ストレージからフレームの実体を取得する
            {'Success':True, 'Response':object}
            {'Success':False, 'Message':string}
        '''
        if 'framename' not in param:
            return {'Success':False, 'Message':'Request parameter error(framename)'}

        framename = param['framename']
        Object    = self.server.storage.get_frame(framename, '.pcm')
        return {'Success':True, 'Response':Object}

    def run(self):
        '''
            クライアントに対するスレッド処理
        '''
        logging.debug("*** Starting: [%s] : %s" % (threading.currentThread().getName(), self.address))
        fb = frame.FrameBuilder()

        request_frame = fb.recv_request(self.socket)
        if 'param' not in request_frame:
            request_frame['param'] = None
        Params = self.resp_hashcall(request_frame['type'], request_frame['param'])
        fb.send_response(self.socket, request_frame['type'], Params)

        self.socket.close()
        logging.debug("*** Existing: [%s]" % (threading.currentThread().getName()))

if '__main__' == __name__:
    server = Server( bind=('172.16.80.30', 15680), listen=5  )
    server.start()

